home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
editors
/
stevie3a.3
< prev
next >
Wrap
Text File
|
1989-03-15
|
61KB
|
2,492 lines
Path: xanth!ukma!mailrus!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i042: stevie - vi-like text editor v35a, Part03/06
Message-ID: <12215@swan.ulowell.edu>
Date: 15 Mar 89 14:57:35 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 2481
Approved: page@swan.ulowell.edu
Submitted-by: grwalter@watcgl.waterloo.edu (Fred Walter)
Posting-number: Volume 89, Issue 42
Archive-name: editors/stevie35a.3
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# charset.c
# edit.c
# help.c
# main.c
# misccmds.c
# screen.c
# This archive created: Tue Mar 14 14:41:34 1989
cat << \SHAR_EOF > charset.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* This file shows how to display characters on the screen. This is approach
* is something of an overkill. It's a remnant from the original code that
* isn't worth messing with for now. TABS are special-cased depending on the
* value of the "list" parameter.
*/
struct charinfo chars[] = {
/* 0 */ 1, NUL,
/* 1 */ 2, "^A",
/* 2 */ 2, "^B",
/* 3 */ 2, "^C",
/* 4 */ 2, "^D",
/* 5 */ 2, "^E",
/* 6 */ 2, "^F",
/* 7 */ 2, "^G",
/* 8 */ 2, "^H",
/* 9 */ 2, "^I",
/* 10 */ 7, "[ERROR]", /* shouldn't happen */
/* 11 */ 2, "^K",
/* 12 */ 2, "^L",
/* 13 */ 2, "^M",
/* 14 */ 2, "^N",
/* 15 */ 2, "^O",
/* 16 */ 2, "^P",
/* 17 */ 2, "^Q",
/* 18 */ 2, "^R",
/* 19 */ 2, "^S",
/* 20 */ 2, "^T",
/* 21 */ 2, "^U",
/* 22 */ 2, "^V",
/* 23 */ 2, "^W",
/* 24 */ 2, "^X",
/* 25 */ 2, "^Y",
/* 26 */ 2, "^Z",
/* 27 */ 2, "^[",
/* 28 */ 2, "^\\",
/* 29 */ 2, "^]",
/* 30 */ 2, "^^",
/* 31 */ 2, "^_",
/* 32 */ 1, " ",
/* 33 */ 1, "!",
/* 34 */ 1, "\"",
/* 35 */ 1, "#",
/* 36 */ 1, "$",
/* 37 */ 1, "%",
/* 38 */ 1, "&",
/* 39 */ 1, "'",
/* 40 */ 1, "(",
/* 41 */ 1, ")",
/* 42 */ 1, "*",
/* 43 */ 1, "+",
/* 44 */ 1, ",",
/* 45 */ 1, "-",
/* 46 */ 1, ".",
/* 47 */ 1, "/",
/* 48 */ 1, "0",
/* 49 */ 1, "1",
/* 50 */ 1, "2",
/* 51 */ 1, "3",
/* 52 */ 1, "4",
/* 53 */ 1, "5",
/* 54 */ 1, "6",
/* 55 */ 1, "7",
/* 56 */ 1, "8",
/* 57 */ 1, "9",
/* 58 */ 1, ":",
/* 59 */ 1, ";",
/* 60 */ 1, "<",
/* 61 */ 1, "=",
/* 62 */ 1, ">",
/* 63 */ 1, "?",
/* 64 */ 1, "@",
/* 65 */ 1, "A",
/* 66 */ 1, "B",
/* 67 */ 1, "C",
/* 68 */ 1, "D",
/* 69 */ 1, "E",
/* 70 */ 1, "F",
/* 71 */ 1, "G",
/* 72 */ 1, "H",
/* 73 */ 1, "I",
/* 74 */ 1, "J",
/* 75 */ 1, "K",
/* 76 */ 1, "L",
/* 77 */ 1, "M",
/* 78 */ 1, "N",
/* 79 */ 1, "O",
/* 80 */ 1, "P",
/* 81 */ 1, "Q",
/* 82 */ 1, "R",
/* 83 */ 1, "S",
/* 84 */ 1, "T",
/* 85 */ 1, "U",
/* 86 */ 1, "V",
/* 87 */ 1, "W",
/* 88 */ 1, "X",
/* 89 */ 1, "Y",
/* 90 */ 1, "Z",
/* 91 */ 1, "[",
/* 92 */ 1, "\\",
/* 93 */ 1, "]",
/* 94 */ 1, "^",
/* 95 */ 1, "_",
/* 96 */ 1, "`",
/* 97 */ 1, "a",
/* 98 */ 1, "b",
/* 99 */ 1, "c",
/* 100 */ 1, "d",
/* 101 */ 1, "e",
/* 102 */ 1, "f",
/* 103 */ 1, "g",
/* 104 */ 1, "h",
/* 105 */ 1, "i",
/* 106 */ 1, "j",
/* 107 */ 1, "k",
/* 108 */ 1, "l",
/* 109 */ 1, "m",
/* 110 */ 1, "n",
/* 111 */ 1, "o",
/* 112 */ 1, "p",
/* 113 */ 1, "q",
/* 114 */ 1, "r",
/* 115 */ 1, "s",
/* 116 */ 1, "t",
/* 117 */ 1, "u",
/* 118 */ 1, "v",
/* 119 */ 1, "w",
/* 120 */ 1, "x",
/* 121 */ 1, "y",
/* 122 */ 1, "z",
/* 123 */ 1, "{",
/* 124 */ 1, "|",
/* 125 */ 1, "}",
/* 126 */ 1, "~",
/* 127 */ 2, "^?",
/* 128 */ 5, "[128]",
/* 129 */ 5, "[129]",
/* 130 */ 5, "[130]",
/* 131 */ 5, "[131]",
/* 132 */ 5, "[132]",
/* 133 */ 5, "[133]",
/* 134 */ 5, "[134]",
/* 135 */ 5, "[135]",
/* 136 */ 5, "[136]",
/* 137 */ 5, "[137]",
/* 138 */ 5, "[138]",
/* 139 */ 5, "[139]",
/* 140 */ 5, "[140]",
/* 141 */ 5, "[141]",
/* 142 */ 5, "[142]",
/* 143 */ 5, "[143]",
/* 144 */ 5, "[144]",
/* 145 */ 5, "[145]",
/* 146 */ 5, "[146]",
/* 147 */ 5, "[147]",
/* 148 */ 5, "[148]",
/* 149 */ 5, "[149]",
/* 150 */ 5, "[150]",
/* 151 */ 5, "[151]",
/* 152 */ 5, "[152]",
/* 153 */ 5, "[153]",
/* 154 */ 5, "[154]",
/* 155 */ 5, "[155]",
/* 156 */ 5, "[156]",
/* 157 */ 5, "[157]",
/* 158 */ 5, "[158]",
/* 159 */ 5, "[159]",
#ifdef AMIGA
/* 160 */ 1, "\240",
/* 161 */ 1, "\241",
/* 162 */ 1, "\242",
/* 163 */ 1, "\243",
/* 164 */ 1, "\244",
/* 165 */ 1, "\245",
/* 166 */ 1, "\246",
/* 167 */ 1, "\247",
/* 168 */ 1, "\250",
/* 169 */ 1, "\251",
/* 170 */ 1, "\252",
/* 171 */ 1, "\253",
/* 172 */ 1, "\254",
/* 173 */ 1, "\255",
/* 174 */ 1, "\256",
/* 175 */ 1, "\257",
/* 176 */ 1, "\260",
/* 177 */ 1, "\261",
/* 178 */ 1, "\262",
/* 179 */ 1, "\263",
/* 180 */ 1, "\264",
/* 181 */ 1, "\265",
/* 182 */ 1, "\266",
/* 183 */ 1, "\267",
/* 184 */ 1, "\270",
/* 185 */ 1, "\271",
/* 186 */ 1, "\272",
/* 187 */ 1, "\273",
/* 188 */ 1, "\274",
/* 189 */ 1, "\275",
/* 190 */ 1, "\276",
/* 191 */ 1, "\277",
/* 192 */ 1, "\300",
/* 193 */ 1, "\301",
/* 194 */ 1, "\302",
/* 195 */ 1, "\303",
/* 196 */ 1, "\304",
/* 197 */ 1, "\305",
/* 198 */ 1, "\306",
/* 199 */ 1, "\307",
/* 200 */ 1, "\310",
/* 201 */ 1, "\311",
/* 202 */ 1, "\312",
/* 203 */ 1, "\313",
/* 204 */ 1, "\314",
/* 205 */ 1, "\315",
/* 206 */ 1, "\316",
/* 207 */ 1, "\317",
/* 208 */ 1, "\320",
/* 209 */ 1, "\321",
/* 210 */ 1, "\322",
/* 211 */ 1, "\323",
/* 212 */ 1, "\324",
/* 213 */ 1, "\325",
/* 214 */ 1, "\326",
/* 215 */ 1, "\327",
/* 216 */ 1, "\330",
/* 217 */ 1, "\331",
/* 218 */ 1, "\332",
/* 219 */ 1, "\333",
/* 220 */ 1, "\334",
/* 221 */ 1, "\335",
/* 222 */ 1, "\336",
/* 223 */ 1, "\337",
/* 224 */ 1, "\340",
/* 225 */ 1, "\341",
/* 226 */ 1, "\342",
/* 227 */ 1, "\343",
/* 228 */ 1, "\344",
/* 229 */ 1, "\345",
/* 230 */ 1, "\346",
/* 231 */ 1, "\347",
/* 232 */ 1, "\350",
/* 233 */ 1, "\351",
/* 234 */ 1, "\352",
/* 235 */ 1, "\353",
/* 236 */ 1, "\354",
/* 237 */ 1, "\355",
/* 238 */ 1, "\356",
/* 239 */ 1, "\357",
/* 240 */ 1, "\360",
/* 241 */ 1, "\361",
/* 242 */ 1, "\362",
/* 243 */ 1, "\363",
/* 244 */ 1, "\364",
/* 245 */ 1, "\365",
/* 246 */ 1, "\366",
/* 247 */ 1, "\367",
/* 248 */ 1, "\370",
/* 249 */ 1, "\371",
/* 250 */ 1, "\372",
/* 251 */ 1, "\373",
/* 252 */ 1, "\374",
/* 253 */ 1, "\375",
/* 254 */ 1, "\376",
/* 255 */ 1, "\377"
#else
/* 160 */ 5, "[160]",
/* 161 */ 5, "[161]",
/* 162 */ 5, "[162]",
/* 163 */ 5, "[163]",
/* 164 */ 5, "[164]",
/* 165 */ 5, "[165]",
/* 166 */ 5, "[166]",
/* 167 */ 5, "[167]",
/* 168 */ 5, "[168]",
/* 169 */ 5, "[169]",
/* 170 */ 5, "[170]",
/* 171 */ 5, "[171]",
/* 172 */ 5, "[172]",
/* 173 */ 5, "[173]",
/* 174 */ 5, "[174]",
/* 175 */ 5, "[175]",
/* 176 */ 5, "[176]",
/* 177 */ 5, "[177]",
/* 178 */ 5, "[178]",
/* 179 */ 5, "[179]",
/* 180 */ 5, "[180]",
/* 181 */ 5, "[181]",
/* 182 */ 5, "[182]",
/* 183 */ 5, "[183]",
/* 184 */ 5, "[184]",
/* 185 */ 5, "[185]",
/* 186 */ 5, "[186]",
/* 187 */ 5, "[187]",
/* 188 */ 5, "[188]",
/* 189 */ 5, "[189]",
/* 190 */ 5, "[190]",
/* 191 */ 5, "[191]",
/* 192 */ 5, "[192]",
/* 193 */ 5, "[193]",
/* 194 */ 5, "[194]",
/* 195 */ 5, "[195]",
/* 196 */ 5, "[196]",
/* 197 */ 5, "[197]",
/* 198 */ 5, "[198]",
/* 199 */ 5, "[199]",
/* 200 */ 5, "[200]",
/* 201 */ 5, "[201]",
/* 202 */ 5, "[202]",
/* 203 */ 5, "[203]",
/* 204 */ 5, "[204]",
/* 205 */ 5, "[205]",
/* 206 */ 5, "[206]",
/* 207 */ 5, "[207]",
/* 208 */ 5, "[208]",
/* 209 */ 5, "[209]",
/* 210 */ 5, "[210]",
/* 211 */ 5, "[211]",
/* 212 */ 5, "[212]",
/* 213 */ 5, "[213]",
/* 214 */ 5, "[214]",
/* 215 */ 5, "[215]",
/* 216 */ 5, "[216]",
/* 217 */ 5, "[217]",
/* 218 */ 5, "[218]",
/* 219 */ 5, "[219]",
/* 220 */ 5, "[220]",
/* 221 */ 5, "[221]",
/* 222 */ 5, "[222]",
/* 223 */ 5, "[223]",
/* 224 */ 5, "[224]",
/* 225 */ 5, "[225]",
/* 226 */ 5, "[226]",
/* 227 */ 5, "[227]",
/* 228 */ 5, "[228]",
/* 229 */ 5, "[229]",
/* 230 */ 5, "[230]",
/* 231 */ 5, "[231]",
/* 232 */ 5, "[232]",
/* 233 */ 5, "[233]",
/* 234 */ 5, "[234]",
/* 235 */ 5, "[235]",
/* 236 */ 5, "[236]",
/* 237 */ 5, "[237]",
/* 238 */ 5, "[238]",
/* 239 */ 5, "[239]",
/* 240 */ 5, "[240]",
/* 241 */ 5, "[241]",
/* 242 */ 5, "[242]",
/* 243 */ 5, "[243]",
/* 244 */ 5, "[244]",
/* 245 */ 5, "[245]",
/* 246 */ 5, "[246]",
/* 247 */ 5, "[247]",
/* 248 */ 5, "[248]",
/* 249 */ 5, "[249]",
/* 250 */ 5, "[250]",
/* 251 */ 5, "[251]",
/* 252 */ 5, "[252]",
/* 253 */ 5, "[253]",
/* 254 */ 5, "[254]",
/* 255 */ 5, "[255]"
#endif
};
SHAR_EOF
cat << \SHAR_EOF > edit.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* This flag is used to make auto-indent work right on lines where only a
* <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
* reset when any other editting is done on the line. If an <ESC> or <RETURN>
* is received, and did_ai is TRUE, the line is truncated.
*/
bool_t did_ai = FALSE;
void
edit()
{
char c;
bool_t literal_next_flag = FALSE;
Prenum = 0;
/* position the display and the cursor at the top of the file. */
*Topchar = *Filemem;
*Curschar = *Filemem;
Cursrow = Curscol = 0;
for (;;) {
if (!RedrawingDisabled) {
cursupdate(); /* Figure out where the cursor is based on
* Curschar. */
if (MustRedrawLine)
redrawline();
if (MustRedrawScreen)
updateRealscreen();
windgoto(Cursrow, Curscol);
}
c = vgetc();
if (State == NORMAL) {
/* We're in the normal (non-insert) mode. */
/* Pick up any leading digits and compute 'Prenum' */
if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) {
Prenum = Prenum * 10 + (c - '0');
continue;
}
/* execute the command */
normal(c);
Prenum = 0;
} else {
if (c == CTRL('V') && !literal_next_flag) {
literal_next_flag = TRUE;
outchar('^');
continue;
}
if (literal_next_flag) {
literal_next_flag = FALSE;
outchar('\b');
if (c != NL) {
did_ai = FALSE;
insertchar(c);
continue;
}
}
switch (c) { /* We're in insert mode */
case ESC: /* an escape ends input mode */
doESCkey:
/*
* If we just did an auto-indent, truncate the line, and put
* the cursor back.
*/
if (did_ai) {
Curschar->linep->s[0] = NUL;
Curschar->index = 0;
did_ai = FALSE;
}
set_want_col = TRUE;
/*
* The cursor should end up on the last inserted character.
* This is an attempt to match the real 'vi', but it may not
* be quite right yet.
*/
if (Curschar->index != 0) {
if (gchar(Curschar) == NUL)
dec(Curschar);
else if (Insbuffptr != NULL)
dec(Curschar);
}
State = NORMAL;
msg("");
if (RedrawingDisabled) {
updateNextscreen(NOT_VALID); /* Update LineSizes. */
cursupdate(); /* Update Topchar and Botchar. */
}
if (!UndoInProgress) {
int n;
char *p;
if (last_command == 'o')
AppendToUndobuff(UNDO_SHIFTJ_STR);
if (Insbuffptr != NULL) {
if (last_command == 'O')
AppendToUndobuff("0");
AppendToRedobuff(Insbuff);
AppendToUndoUndobuff(Insbuff);
n = 0;
for (p = Insbuff; *p != NUL; p++) {
if (*p == NL) {
if (n) {
AppendNumberToUndobuff(n);
AppendToUndobuff("dl");
n = 0;
}
AppendToUndobuff(UNDO_SHIFTJ_STR);
} else
n++;
}
if (n) {
AppendNumberToUndobuff(n);
AppendToUndobuff("dl");
}
}
if (last_command == 'c') {
AppendToUndobuff(mkstr(last_command_char));
AppendToUndobuff(Yankbuff);
AppendToUndobuff(ESC_STR);
}
AppendToRedobuff(ESC_STR);
AppendToUndoUndobuff(ESC_STR);
if (last_command == 'O')
AppendToUndobuff(UNDO_SHIFTJ_STR);
}
break;
case CTRL('D'):
/*
* Control-D is treated as a backspace in insert mode to make
* auto-indent easier. This isn't completely compatible with
* vi, but it's a lot easier than doing it exactly right, and
* the difference isn't very noticeable.
*/
case BS:
/* can't backup past starting point */
if (Curschar->linep == Insstart->linep &&
Curschar->index <= Insstart->index) {
beep();
break;
}
/* can't backup to a previous line */
if (Curschar->linep != Insstart->linep &&
Curschar->index <= 0) {
beep();
break;
}
did_ai = FALSE;
dec(Curschar);
delchar(TRUE, FALSE);
/*
* It's a little strange to put backspaces into the redo
* buffer, but it makes auto-indent a lot easier to deal
* with.
*/
AppendToInsbuff(BS_STR);
if (!RedrawingDisabled) {
cursupdate();
updateline();
}
break;
case CR:
case NL:
AppendToInsbuff(NL_STR);
if (!OpenForward(!RedrawingDisabled))
goto doESCkey; /* out of memory */
if (!RedrawingDisabled)
windgoto(Cursrow, Curscol);
break;
default:
did_ai = FALSE;
insertchar(c);
break;
}
}
}
}
/*
* Special characters in this context are those that need processing other
* than the simple insertion that can be performed here. This includes ESC
* which terminates the insert, and CR/NL which need special processing to
* open up a new line. This routine tries to optimize insertions performed by
* the "redo", "undo" or "put" commands, so it needs to know when it should
* stop and defer processing to the "normal" mechanism.
*/
#define ISSPECIAL(c) ((c) == BS || (c) == NL || (c) == CR || (c) == ESC)
void
insertchar(c)
char c;
{
if (anyinput()) { /* If there's any pending input, grab up to
* MAX_COLUMNS at once. */
char p[MAX_COLUMNS + 1];
int i;
p[0] = c;
i = 1;
c = vpeekc();
while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) {
p[i++] = vgetc();
c = vpeekc();
}
p[i] = '\0';
insstr(p);
AppendToInsbuff(p);
} else {
inschar(c);
AppendToInsbuff(mkstr(c));
}
if (!RedrawingDisabled)
updateline();
}
void
getout(r)
int r;
{
windgoto(Rows - 1, 0);
putchar('\r');
putchar('\n');
windexit(r);
}
void
scrolldown(nlines)
int nlines;
{
register LPtr *p;
register int done = 0; /* total # of physical lines done */
/* Scroll up 'nlines' lines. */
while (nlines--) {
if ((p = prevline(Topchar)) == NULL)
break;
done += plines(p);
*Topchar = *p;
if (Curschar->linep == Botchar->linep->prev)
*Curschar = *prevline(Curschar);
}
s_ins(0, done, Rows, Columns);
}
void
scrollup(nlines)
int nlines;
{
register LPtr *p;
register int done = 0; /* total # of physical lines done */
register int pl; /* # of plines for the current line */
/* Scroll down 'nlines' lines. */
while (nlines--) {
pl = plines(Topchar);
if ((p = nextline(Topchar)) == NULL)
break;
done += pl;
if (Curschar->linep == Topchar->linep)
*Curschar = *p;
*Topchar = *p;
}
s_del(0, done, Rows, Columns);
}
/*
* oneright oneleft onedown oneup
*
* Move one char {right,left,down,up}. Return TRUE when sucessful, FALSE when
* we hit a boundary (of a line, or the file).
*/
bool_t
oneright()
{
set_want_col = TRUE;
switch (inc(Curschar)) {
case 0:
return TRUE;
case 1:
dec(Curschar); /* crossed a line, so back up */
/* FALLTHROUGH */
case -1:
return FALSE;
}
return FALSE; /* PARANOIA: should never reach here */
}
bool_t
oneleft()
{
set_want_col = TRUE;
switch (dec(Curschar)) {
case 0:
return TRUE;
case 1:
inc(Curschar); /* crossed a line, so back up */
/* FALLTHROUGH */
case -1:
return FALSE;
}
return FALSE; /* PARANOIA: should never reach here */
}
void
beginline(flag)
bool_t flag;
{
while (oneleft());
if (flag) {
while (isspace(gchar(Curschar)) && oneright());
}
set_want_col = TRUE;
}
bool_t
oneup(n)
{
LPtr p, *np;
int k;
p = *Curschar;
for (k = 0; k < n; k++) {
/* Look for the previous line */
if ((np = prevline(&p)) == NULL) {
/* If we've at least backed up a little .. */
if (k > 0)
break; /* to update the cursor, etc. */
else
return FALSE;
}
p = *np;
}
*Curschar = p;
cursupdate(); /* make sure Topchar is valid */
/* try to advance to the column we want to be at */
*Curschar = *coladvance(&p, Curswant);
return TRUE;
}
bool_t
onedown(n)
{
LPtr p, *np;
int k;
p = *Curschar;
for (k = 0; k < n; k++) {
/* Look for the next line */
if ((np = nextline(&p)) == NULL) {
if (k > 0)
break;
else
return FALSE;
}
p = *np;
}
cursupdate(); /* make sure Topchar is valid */
/* try to advance to the column we want to be at */
*Curschar = *coladvance(&p, Curswant);
return TRUE;
}
SHAR_EOF
cat << \SHAR_EOF > help.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
extern char *Version;
static int helprow;
#ifdef HELP
#ifdef MEGAMAX
overlay "help"
#endif
static void longline();
bool_t
help()
{
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Positioning within file\n\
=======================\n\
^F Forward screenfull Worked on by:\n\
^B Backward screenfull Tim Thompson\n");
longline("\
^D scroll down half screen Tony Andrews\n\
^U scroll up half screen G.R. (Fred) Walter\n");
longline("\
G Goto line (end default)\n\
]] next function\n\
[[ previous function\n\
/re next occurence of regular expression 're'\n");
longline("\
?re prior occurence of regular expression 're'\n\
n repeat last / or ?\n\
N reverse last / or ?\n\
% find matching (, ), {, }, [, or ]\n");
longline("\
\n\
Adjusting the screen\n\
====================\n\
^L Redraw the screen\n\
^E scroll window down 1 line\n\
^Y scroll window up 1 line\n");
longline("\
z<RETURN> redraw, current line at top\n\
z- ... at bottom\n\
z. ... at center\n");
windgoto(0, 32);
longline(Version);
#ifdef AMIGA
longline(" ");
longline(__DATE__);
longline(" ");
longline(__TIME__);
#endif
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Character Positioning\n\
=====================\n\
^ first non-white\n\
0 beginning of line\n\
$ end of line\n\
h backward\n");
longline("\
l forward\n\
^H same as h\n\
space same as l\n\
fx find 'x' forward\n");
longline("\
Fx find 'x' backward\n\
tx upto 'x' forward\n\
Tx upto 'x' backward\n\
; Repeat last f, F, t, or T\n");
longline("\
, inverse of ;\n\
| to specified column\n\
% find matching (, ), {, }, [, or ]\n");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Line Positioning\n\
=====================\n\
H home window line\n\
L last window line\n\
M middle window line\n");
longline("\
+ next line, at first non-white\n\
- previous line, at first non-white\n\
CR return, same as +\n\
j next line, same column\n\
k previous line, same column\n");
longline("\
\n\
Marking and Returning\n\
=====================\n\
`` previous context\n\
'' ... at first non-white in line\n");
longline("\
mx mark position with letter 'x'\n\
`x to mark 'x'\n\
'x ... at first non-white in line\n");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Insert and Replace\n\
==================\n\
a append after cursor\n\
i insert before cursor\n\
A append at end of line\n\
I insert before first non-blank\n");
longline("\
o open line below\n\
O open line above\n\
rx replace single char with 'x'\n\
R replace characters (not yet)\n\
~ replace character under cursor with other case\n");
longline("\
\n\
Words, sentences, paragraphs\n\
============================\n\
w word forward\n\
b back word\n\
e end of word\n\
) to next sentence (not yet)\n\
} to next paragraph (not yet)\n");
longline("\
( back sentence (not yet)\n\
{ back paragraph (not yet)\n\
W blank delimited word\n\
B back W\n\
E to end of W");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Undo & Redo\n\
=============\n\
u undo last change\n\
U restore current line (not yet)\n\
. repeat last change\n");
longline("\
\n\
File manipulation\n\
=================\n");
longline("\
:w write back changes\n\
:wq write and quit\n\
:x write if modified, and quit\n\
:q quit\n\
:q! quit, discard changes\n\
:e name edit file 'name'\n");
longline("\
:e! reedit, discard changes\n\
:e # edit alternate file\n\
:w name write file 'name'\n");
longline("\
:n edit next file in arglist\n\
:n args specify new arglist (not yet)\n\
:rew rewind arglist\n\
:f show current file and lines\n");
longline("\
:f file change current file name\n\
:ta tag to tag file entry 'tag'\n\
^] :ta, current word is tag");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\
Operators (double to affect lines)\n\
==================================\n\
d delete\n\
c change\n");
longline("\
< left shift\n\
> right shift\n\
y yank to buffer\n");
longline("\n\
Yank and Put\n\
============\n\
p put back text\n\
P put before\n\
Y yank lines");
windgoto(helprow = Rows - 2, 47);
longline("<Press space bar to continue>\n");
windgoto(helprow = Rows - 1, 47);
longline("<Any other key will quit>");
if (vgetc() != ' ')
return TRUE;
outstr(T_ED);
windgoto(helprow = 0, 0);
longline("\n\
Miscellaneous operations\n\
========================\n\
C change rest of line\n\
D delete rest of line\n\
s substitute chars\n");
longline("\
S substitute lines (not yet)\n\
J join lines\n\
x delete characters\n\
X ... before cursor\n\
:[range]s/search/replace/[g]\n\
:[range]g/search[/p|/d]\n\
:[range]d delete range of lines\n");
windgoto(helprow = Rows - 1, 47);
longline("<Press any key>");
vgetc();
return TRUE;
}
static void
longline(p)
char *p;
{
# ifdef AMIGA
outstr(p);
# else
char *s;
for (s = p; *s; s++) {
if (*s == '\n')
windgoto(++helprow, 0);
else
outchar(*s);
}
# endif
}
#else
bool_t
help()
{
msg("Sorry, help not configured");
return FALSE;
}
#endif
SHAR_EOF
cat << \SHAR_EOF > main.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
int Rows; /* Number of Rows and Columns */
int Columns; /* in the current window. */
char *Realscreen = NULL; /* What's currently on the screen, a
* single array of size Rows*Columns. */
char *Nextscreen = NULL; /* What's to be put on the screen. */
int NumLineSizes = 0; /* # of active LineSizes */
LINE **LinePointers = NULL; /* Pointer to the line for LineSizes */
char *LineSizes = NULL; /* Size of a line (pline output) */
char *Filename = NULL;/* Current file name */
LPtr *Filemem; /* The contents of the file, as a single
* array. */
LPtr *Filetop; /* Line 'above' the start of the file */
LPtr *Fileend; /* Pointer to the end of the file in Filemem.
* (It points to the byte AFTER the last
* byte.) */
LPtr *Topchar; /* Pointer to the byte in Filemem which is in
* the upper left corner of the screen. */
LPtr *Botchar; /* Pointer to the byte in Filemem which is
* just off the bottom of the screen. */
LPtr *Curschar; /* Pointer to byte in Filemem at which the
* cursor is currently placed. */
int Curscol; /* Current position of cursor (column) */
int Cursrow; /* Current position of cursor (row) */
int Cursvcol; /* Current virtual column, the column number
* of the file's actual line, as opposed to
* the column number we're at on the screen.
* This makes a difference on lines that span
* more than one screen line. */
int Curswant = 0; /* The column we'd like to be at. This is
* used try to stay in the same column
* through up/down cursor motions. */
bool_t set_want_col; /* If set, then update Curswant the next time
* through cursupdate() to the current
* virtual column. */
int State = NORMAL; /* This is the current state of the command
* interpreter. */
int Prenum = 0; /* The (optional) number before a command. */
LPtr *Insstart; /* This is where the latest insert/append
* mode started. */
bool_t Changed = FALSE;/* Set to TRUE if something in the file has
* been changed and not written out. */
char *IObuff; /* file reads are done, one line at a time,
* into this buffer; as well as sprintf's */
char *Insbuffptr = NULL;
char *Insbuff; /* Each insertion gets stuffed into this
* buffer. */
char *Readbuffptr = NULL;
char *Readbuff; /* Having this buffer allows STEVIE to easily
* make itself do commands */
char *Redobuffptr = NULL;
char *Redobuff; /* Each command should stuff characters into
* this buffer that will re-execute itself. */
bool_t UndoInProgress = FALSE; /* Set to TRUE if undo'ing */
char *Undobuffptr = NULL;
char *Undobuff; /* Each command should stuff characters into
* this buffer that will undo its effects. */
char *UndoUndobuffptr = NULL;
char *UndoUndobuff; /* Each command should stuff characters into
* this buffer that will undo its undo. */
char *Yankbuffptr = NULL;
char *Yankbuff; /* Yank buffer */
char last_command = NUL; /* last command */
char last_command_char = NUL; /* character needed to undo
* last command */
bool_t RedrawingDisabled = FALSE; /* Set to TRUE if undo'ing or
* put'ing */
bool_t MustRedrawLine = FALSE; /* Set to TRUE if we must redraw the
* current line */
bool_t MustRedrawScreen = TRUE; /* Set to TRUE if we must
* redraw the screen */
char **files; /* list of input files */
int numfiles; /* number of input files */
int curfile; /* number of the current file */
static void
usage()
{
fprintf(stderr, "usage: stevie [file ...]\n");
fprintf(stderr, " stevie -t tag\n");
fprintf(stderr, " stevie +[num] file\n");
fprintf(stderr, " stevie +/pat file\n");
exit(1);
}
#ifdef AMIGA
void
#else
int
#endif
main(argc, argv)
int argc;
char **argv;
{
char *initstr, *getenv(); /* init string from the environment */
char *tag = NULL; /* tag from command line */
char *pat = NULL; /* pattern from command line */
int line = -1; /* line number from command line */
int atoi();
#ifdef AMIGA
/*
* This won't be needed if you have a version of Lattice 4.01 without broken
* break signal handling.
*/
(void) signal(SIGINT, SIG_IGN);
#endif
/*
* Process the command line arguments.
*/
if (argc > 1) {
switch (argv[1][0]) {
case '-': /* -t tag */
if (argv[1][1] != 't')
usage();
if (argv[2] == NULL)
usage();
Filename = NULL;
tag = argv[2];
numfiles = 1;
break;
case '+': /* +n or +/pat */
if (argv[1][1] == '/') {
if (argv[2] == NULL)
usage();
Filename = strsave(argv[2]);
pat = &(argv[1][1]);
numfiles = 1;
} else if (isdigit(argv[1][1]) || argv[1][1] == NUL) {
if (argv[2] == NULL)
usage();
Filename = strsave(argv[2]);
numfiles = 1;
line = (isdigit(argv[1][1])) ?
atoi(&(argv[1][1])) : 0;
} else
usage();
break;
default: /* must be a file name */
Filename = strsave(argv[1]);
files = &(argv[1]);
numfiles = argc - 1;
break;
}
} else {
Filename = NULL;
numfiles = 1;
}
curfile = 0;
windinit();
/*
* Allocate LPtr structures for all the various position pointers
*/
if ((Filemem = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Filetop = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Fileend = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Topchar = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Botchar = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Curschar = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Insstart = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
/*
* Allocate space for the many buffers
*/
if ((IObuff = alloc(IOSIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Insbuff = alloc(INSERT_SIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Readbuff = alloc(READSIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Redobuff = alloc(REDO_UNDO_SIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Undobuff = alloc(REDO_UNDO_SIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((UndoUndobuff = alloc(REDO_UNDO_SIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
if ((Yankbuff = alloc(YANKSIZE)) == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
screenalloc();
filealloc(); /* Initialize Filemem, Filetop & Fileend */
screenclear();
if ((initstr = getenv("EXINIT")) != NULL) {
char *lp, buf[128];
if ((lp = getenv("LINES")) != NULL) {
sprintf(buf, "%s lines=%s", initstr, lp);
readcmdline(':', buf);
} else
readcmdline(':', initstr);
}
if (Filename != NULL) {
if (readfile(Filename, Filemem, FALSE))
filemess("[New File]");
} else
msg("Empty Buffer");
setpcmark();
updateNextscreen(NOT_VALID);
if (tag) {
stuffReadbuff(":ta ");
stuffReadbuff(tag);
stuffReadbuff("\n");
} else if (pat) {
stuffReadbuff(pat);
stuffReadbuff("\n");
} else if (line >= 0) {
if (line > 0)
stuffnumReadbuff(line);
stuffReadbuff("G");
}
edit();
windexit(0);
}
void
stuffReadbuff(s)
char *s;
{
if (strlen(s) == 0)
return;
if (Readbuffptr == NULL) {
if ((strlen(s) + 1) < READSIZE) {
strcpy(Readbuff, s);
Readbuffptr = Readbuff;
return;
}
} else if ((strlen(Readbuff) + (strlen(s) + 1)) < READSIZE) {
strcat(Readbuff, s);
return;
}
emsg("Couldn't stuffReadbuff() - clearing Readbuff\n");
*Readbuff = NUL;
Readbuffptr = NULL;
}
void
stuffnumReadbuff(n)
int n;
{
char buf[32];
sprintf(buf, "%d", n);
stuffReadbuff(buf);
}
/* OPTRESULT */
char
vgetc()
{
int c;
/*
* inchar() may map special keys by using stuffReadbuff(). If it does so,
* it returns -1 so we know to loop here to get a real char.
*/
do {
if (Readbuffptr != NULL) {
char nextc = *Readbuffptr++;
if (*Readbuffptr == NUL) {
*Readbuff = NUL;
Readbuffptr = NULL;
}
return (nextc);
}
c = inchar();
} while (c == -1);
return (char) c;
}
char
vpeekc()
{
if (Readbuffptr != NULL)
return (*Readbuffptr);
return (NUL);
}
SHAR_EOF
cat << \SHAR_EOF > misccmds.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
extern int did_ai;
/*
* OpenForward
*
* Add a blank line below the current line.
*/
bool_t
OpenForward(can_ai)
int can_ai;
{
LINE *l;
LPtr *next;
char *s; /* string to be moved to new line, if any */
int newindex = 0; /* index of the cursor on the new
* line */
/*
* If we're in insert mode, we need to move the remainder of the current
* line onto the new line. Otherwise the new line is left blank.
*/
if (State == INSERT)
s = &Curschar->linep->s[Curschar->index];
else
s = "";
if ((next = nextline(Curschar)) == NULL) /* open on last line */
next = Fileend;
/*
* By asking for as much space as the prior line had we make sure that
* we'll have enough space for any auto-indenting.
*/
if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) {
emsg("out of memory");
beep();
sleep(2);
return (FALSE);
}
if (can_ai && P(P_AI)) {
char *p;
/*
* Copy prior line, and truncate after white space
*/
strcpy(l->s, Curschar->linep->s);
for (p = l->s; *p == ' ' || *p == TAB; p++);
*p = NUL;
newindex = p - l->s;
AppendToInsbuff(l->s);
if (*s != NUL)
strcat(l->s, s);
/*
* If we just did an auto-indent, then we didn't type anything on the
* prior line, and it should be truncated.
*/
if (did_ai)
Curschar->linep->s[0] = NUL;
did_ai = TRUE;
} else if (*s != NUL) {
strcpy(l->s, s); /* copy string to new line */
}
if (State == INSERT) /* truncate current line at cursor */
*s = NUL;
Curschar->linep->next = l; /* link neighbors to new line */
next->linep->prev = l;
l->prev = Curschar->linep; /* link new line to neighbors */
l->next = next->linep;
if (next == Fileend) { /* new line at end */
l->num = Curschar->linep->num + LINEINC;
} else if ((l->prev->num) + 1 == l->next->num) { /* no gap, renumber */
renum();
} else { /* stick it in the middle */
long lnum;
lnum = (l->prev->num + l->next->num) / 2;
l->num = lnum;
}
if (!RedrawingDisabled) {
/*
* Get the cursor to the start of the line, so that 'Cursrow' gets
* set to the right physical line number for the stuff that
* follows...
*/
Curschar->index = 0;
cursupdate();
/*
* If we're doing an open on the last logical line, then go ahead and
* scroll the screen up. Otherwise, just insert a blank line at the
* right place. We use calls to plines() in case the cursor is
* resting on a long line.
*/
if (Cursrow + plines(Curschar) == (Rows - 1))
scrollup(1);
else
s_ins(Cursrow + plines(Curschar), 1, Rows, Columns);
}
*Curschar = *nextline(Curschar); /* cursor moves down */
Curschar->index = newindex;
if (!RedrawingDisabled) {
/* because Botchar is now invalid */
updateNextscreen(VALID_TO_CURSCHAR);
cursupdate(); /* update Cursrow before insert */
}
CHANGED;
return (TRUE);
}
/*
* OpenBackward
*
* Add a blank line above the current line.
*/
bool_t
OpenBackward(can_ai)
int can_ai;
{
LINE *l;
LINE *prev;
int newindex = 0; /* index of the cursor on the new
* line */
prev = Curschar->linep->prev;
if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) {
emsg("out of memory");
beep();
sleep(2);
return (FALSE);
}
Curschar->linep->prev = l; /* link neighbors to new line */
prev->next = l;
l->next = Curschar->linep; /* link new line to neighbors */
l->prev = prev;
if (can_ai && P(P_AI)) {
char *p;
/*
* Copy current line, and truncate after white space
*/
strcpy(l->s, Curschar->linep->s);
for (p = l->s; *p == ' ' || *p == TAB; p++);
*p = NUL;
newindex = p - l->s;
AppendToInsbuff(l->s);
did_ai = TRUE;
}
Curschar->linep = Curschar->linep->prev;
Curschar->index = newindex;
if (prev == Filetop->linep) { /* new start of file */
Filemem->linep = l;
renum();
} else if ((l->prev->num) + 1 == l->next->num) { /* no gap, renumber */
renum();
} else { /* stick it in the middle */
long lnum;
lnum = (l->prev->num + l->next->num) / 2;
l->num = lnum;
}
if (!RedrawingDisabled) {
if (LINEOF(Curschar) < LINEOF(Topchar)) {
Topchar->linep = Curschar->linep;
updateNextscreen(NOT_VALID);
} else {
updateNextscreen(VALID_TO_CURSCHAR);
}
cursupdate(); /* update Cursrow before insert */
if (Cursrow != 0)
s_ins(Cursrow, 1, Rows, Columns); /* insert a physical line */
}
CHANGED;
return (TRUE);
}
int
cntllines(pbegin, pend)
LPtr *pbegin, *pend;
{
register LINE *lp;
register int lnum = 1;
for (lp = pbegin->linep; lp != pend->linep; lp = lp->next)
lnum++;
return (lnum);
}
/*
* plines(p) - return the number of physical screen lines taken by line 'p'
*/
int
plines(p)
LPtr *p;
{
register int col = 0;
register char *s;
if (p == NULL) {
fprintf(stderr, "plines(p) : p == NULL ????");
return (0);
}
s = p->linep->s;
if (*s == NUL) /* empty line */
return 1;
for (; *s != NUL; s++) {
if (*s == TAB && !P(P_LS))
col += P(P_TS) - (col % P(P_TS));
else
col += chars[(unsigned) (*s & 0xff)].ch_size;
}
/*
* If list mode is on, then the '$' at the end of the line takes up one
* extra column.
*/
if (P(P_LS))
col += 1;
/*
* If 'number' mode is on, add another 8.
*/
if (P(P_NU))
col += 8;
return ((col + (Columns - 1)) / Columns);
}
void
fileinfo()
{
long l1, l2;
char buf[MAX_COLUMNS + 1];
if (bufempty()) {
msg("Buffer Empty");
return;
}
l1 = cntllines(Filemem, Curschar);
l2 = cntllines(Filemem, Fileend) - 1;
sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --",
(Filename != NULL) ? Filename : "No File",
Changed ? " [Modified]" : "",
l1, l2, (l1 * 100) / l2);
msg(buf);
}
/*
* gotoline(n) - return a pointer to line 'n'
*
* Returns a pointer to the last line of the file if n is zero, or beyond the
* end of the file.
*/
LPtr *
gotoline(n)
int n;
{
static LPtr l;
l.index = 0;
if (n == 0)
l = *prevline(Fileend);
else {
LPtr *p;
for (l = *Filemem; --n > 0; l = *p)
if ((p = nextline(&l)) == NULL)
break;
}
return &l;
}
void
inschar(c)
char c;
{
register char *p;
register char *pend;
/* make room for the new char. */
if (!canincrease(1))
return;
p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1];
pend = &Curschar->linep->s[Curschar->index];
for (; p > pend; p--)
*p = *(p - 1);
*p = c;
if (RedrawingDisabled) {
Curschar->index++;
return;
}
/*
* If we're in insert mode and showmatch mode is set, then check for
* right parens and braces. If there isn't a match, then beep. If there
* is a match AND it's on the screen, then flash to it briefly. If it
* isn't on the screen, don't do anything.
*/
if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) {
LPtr *lpos, csave;
if ((lpos = showmatch()) == NULL) /* no match, so beep */
beep();
else if (LINEOF(lpos) >= LINEOF(Topchar)) {
updateNextscreen(VALID_TO_CURSCHAR); /* show the new char
* first */
updateRealscreen();
csave = *Curschar;
*Curschar = *lpos; /* move to matching char */
cursupdate();
windgoto(Cursrow, Curscol);
delay(); /* brief pause */
*Curschar = csave; /* restore cursor position */
cursupdate();
}
}
inc(Curschar);
CHANGED;
}
void
insstr(s)
register char *s;
{
register char *p;
register char *pend;
register int n = strlen(s);
/* Move everything in the file over to make */
/* room for the new string. */
if (!canincrease(n))
return;
p = &Curschar->linep->s[strlen(Curschar->linep->s) + n];
pend = &Curschar->linep->s[Curschar->index];
for (; p > pend; p--)
*p = *(p - n);
for (; n > 0; n--) {
*p++ = *s++;
Curschar->index++;
}
CHANGED;
}
bool_t
delchar(fixpos, undo)
bool_t fixpos; /* if TRUE fix the cursor position when done */
bool_t undo; /* if TRUE put char deleted into Undo buffer */
{
int i;
/* Check for degenerate case; there's nothing in the file. */
if (bufempty())
return FALSE;
if (lineempty(Curschar)) /* can't do anything */
return FALSE;
if (undo)
AppendToUndobuff(mkstr(gchar(Curschar)));
/* Delete the char. at Curschar by shifting everything in the line down. */
for (i = Curschar->index + 1; i < Curschar->linep->size; i++)
Curschar->linep->s[i - 1] = Curschar->linep->s[i];
/*
* If we just took off the last character of a non-blank line, we don't
* want to end up positioned at the newline.
*/
if (fixpos) {
if (gchar(Curschar) == NUL && Curschar->index > 0 && State != INSERT)
Curschar->index--;
}
CHANGED;
return TRUE;
}
void
delline(nlines, can_update)
int nlines;
bool_t can_update;
{
register LINE *p;
register LINE *q;
int doscreen; /* if true, update the screen */
int num_plines = 0;
doscreen = can_update;
/*
* There's no point in keeping the screen updated if we're deleting more
* than a screen's worth of lines.
*/
if (nlines > (Rows - 1) && can_update) {
doscreen = FALSE;
/* flaky way to clear rest of screen */
s_del(Cursrow, Rows - 1, Rows, Columns);
}
while (nlines-- > 0) {
if (bufempty()) /* nothing to delete */
break;
if (buf1line()) { /* just clear the line */
Curschar->linep->s[0] = NUL;
Curschar->index = 0;
break;
}
p = Curschar->linep->prev;
q = Curschar->linep->next;
if (p == Filetop->linep) { /* first line of file so... */
Filemem->linep = q; /* adjust start of file */
Topchar->linep = q; /* and screen */
}
p->next = q;
q->prev = p;
clrmark(Curschar->linep); /* clear marks for the line */
/*
* Set up to delete the correct number of physical lines on the
* screen
*/
if (doscreen)
num_plines += plines(Curschar);
/*
* If deleting the top line on the screen, adjust Topchar
*/
if (Topchar->linep == Curschar->linep)
Topchar->linep = q;
free(Curschar->linep->s);
free((char *) (Curschar->linep));
Curschar->linep = q;
Curschar->index = 0; /* is this right? */
CHANGED;
/* If we delete the last line in the file, back up */
if (Curschar->linep == Fileend->linep) {
Curschar->linep = Curschar->linep->prev;
/* and don't try to delete any more lines */
break;
}
}
/*
* Delete the correct number of physical lines on the screen
*/
if (doscreen && num_plines > 0)
s_del(Cursrow, num_plines, Rows, Columns);
}
SHAR_EOF
cat << \SHAR_EOF > screen.c
/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
#include "stevie.h"
/*
* The following variable is set (in cursupdate) to the number of physical
* lines taken by the line the cursor is on. We use this to avoid extra calls
* to plines(). The optimized routines updateline() and redrawline()
* make sure that the size of the cursor line hasn't changed. If so, lines below
* the cursor will move up or down and we need to call the routines
* updateNextscreen() and updateRealscreen() to examine the entire screen.
*/
static int Cline_size; /* size (in rows) of the cursor line */
static int Cline_row; /* starting row of the cursor line */
/*
* updateline() - like updateNextscreen() but only for cursor line
*
* This determines whether or not we need to call updateNextscreen() to examine
* the entire screen for changes. This occurs if the size of the cursor line
* (in rows) hasn't changed.
*/
void
updateline()
{
register int row;
register int col;
register char *screenp;
register char c;
LPtr memp;
register char *nextrow;
char extra[16];
char *p_extra;
int n_extra;
int n;
bool_t eof;
int lno; /* number of the line we're doing */
int coff; /* column offset */
MustRedrawLine = TRUE;
coff = P(P_NU) ? 8 : 0;
/*
* This should be done more efficiently.
*/
if (P(P_NU))
lno = cntllines(Filemem, Curschar);
screenp = Nextscreen + (Cline_row * Columns);
memp = *Curschar;
memp.index = 0;
eof = FALSE;
col = 0;
row = Cline_row;
p_extra = NULL;
n_extra = 0;
if (P(P_NU)) {
strcpy(extra, mkline(lno));
p_extra = extra;
n_extra = 8;
}
while (!eof) {
/* Get the next character to put on the screen. */
/*
* The 'extra' array contains the extra stuff that is inserted to
* represent special characters (tabs, and other non-printable stuff.
* The order in the 'extra' array is reversed.
*/
if (n_extra > 0) {
c = *p_extra++;
n_extra--;
} else {
c = gchar(&memp);
if (inc(&memp) == -1)
eof = TRUE;
/*
* when getting a character from the file, we may have to turn it
* into something else on the way to putting it into
* 'Nextscreen'.
*/
if (c == TAB && !P(P_LS)) {
strcpy(extra, " ");
p_extra = extra;
/* tab amount depends on current column */
n_extra = ((P(P_TS) - 1) - (col - coff) % P(P_TS));
c = ' ';
} else if (c == NUL && P(P_LS)) {
extra[0] = NUL;
p_extra = extra;
n_extra = 1;
c = '$';
} else if (c != NUL && (n = chars[c].ch_size) > 1) {
p_extra = chars[c].ch_str;
c = *p_extra++;
n_extra = n - 1;
}
}
if (c == NUL) {
row++;
/* get pointer to start of next row */
nextrow = Nextscreen + (row * Columns);
/* blank out the rest of this row */
while (screenp < nextrow)
*screenp++ = ' ';
break;
}
if (col >= Columns) {
row++;
col = 0;
}
/* store the character in Nextscreen */
*screenp++ = c;
col++;
}
if ((row - Cline_row) != Cline_size) {
updateNextscreen(VALID_TO_CURSCHAR);
}
}
/*
* redrawline
*
* Like updateRealscreen() but only for the cursor line.
*/
void
redrawline()
{
register char *np = Nextscreen + (Cline_row * Columns);
register char *rp = Realscreen + (Cline_row * Columns);
register char *endline;
register int row, col;
int gorow = -1, gocol = -1;
if (RedrawingDisabled)
return;
if (!MustRedrawLine && !MustRedrawScreen)
return;
if (MustRedrawScreen) {
msg("STEVIE internal error: redrawline called");
sleep(5);
}
endline = np + (Cline_size * Columns);
row = Cline_row;
col = 0;
outstr(T_CI); /* disable cursor */
for (; np < endline; np++, rp++) {
/* If desired screen (contents of Nextscreen) does not */
/* match what's really there, put it there. */
if (*np != *rp) {
/* if we are positioned at the right place, */
/* we don't have to use windgoto(). */
if (gocol != col || gorow != row) {
/*
* If we're just off by one, don't send an entire esc. seq.
* (this happens a lot!)
*/
if (gorow == row && gocol + 1 == col) {
outchar(*(np - 1));
gocol++;
} else
windgoto(gorow = row, gocol = col);
}
outchar(*rp = *np);
gocol++;
}
if (++col >= Columns) {
col = 0;
row++;
}
}
outstr(T_CV); /* enable cursor again */
MustRedrawScreen = FALSE;
}
/*
* prt_line() - print the given line
*/
void
prt_line(s)
char *s;
{
register int si = 0;
register int c;
register int col = 0;
char extra[16];
int n_extra = 0;
int n;
for (;;) {
if (n_extra > 0)
c = extra[--n_extra];
else {
c = s[si++];
if (c == TAB && !P(P_LS)) {
strcpy(extra, " ");
/* tab amount depends on current column */
n_extra = (P(P_TS) - 1) - col % P(P_TS);
c = ' ';
} else if (c == NUL && P(P_LS)) {
extra[0] = NUL;
n_extra = 1;
c = '$';
} else if (c != NUL && (n = chars[c].ch_size) > 1) {
char *p;
n_extra = 0;
p = chars[c].ch_str;
/* copy 'ch-str'ing into 'extra' in reverse */
while (n > 1)
extra[n_extra++] = p[--n];
c = p[0];
}
}
if (c == NUL)
break;
outchar(c);
col++;
}
}
void
screenclear()
{
register char *rp;
register char *np;
register char *end;
register int i;
outstr(T_ED); /* clear the display */
rp = Realscreen;
end = Realscreen + Rows * Columns;
np = Nextscreen;
/* blank out the stored screens */
while (rp != end)
*rp++ = *np++ = ' ';
/* clear screen info */
for (i = 0; i < Rows; i++) {
LinePointers[i] = NULL;
LineSizes[i] = '\0';
}
NumLineSizes = 0;
}
void
cursupdate()
{
LPtr *p;
LPtr *pp;
char c;
int incr, nlines;
int i;
int didincr;
if (bufempty()) { /* special case - file is empty */
*Topchar = *Filemem;
*Curschar = *Filemem;
for (i = 0; i < Rows; i++)
LineSizes[i] = 0;
} else if (LINEOF(Curschar) < LINEOF(Topchar)) {
nlines = cntllines(Curschar, Topchar);
/*
* if the cursor is above the top of the screen, put it at the top of
* the screen..
*/
*Topchar = *Curschar;
Topchar->index = 0;
/*
* ... and, if we weren't very close to begin with, we scroll so that
* the line is close to the middle.
*/
if (nlines > Rows / 3) {
p = Topchar;
for (i = 0; i < Rows / 3; i += plines(p)) {
pp = prevline(p);
if (pp == NULL)
break;
p = pp;
}
*Topchar = *p;
} else
s_ins(0, nlines - 1, Rows, Columns);
updateNextscreen(VALID);
} else if (LINEOF(Curschar) >= LINEOF(Botchar)) {
nlines = cntllines(Botchar, Curschar);
/*
* If the cursor is off the bottom of the screen, put it at the top
* of the screen.. ... and back up
*/
if (nlines > Rows / 3) {
p = Curschar;
for (i = 0; i < (2 * Rows) / 3; i += plines(p)) {
pp = prevline(p);
if (pp == NULL)
break;
p = pp;
}
*Topchar = *p;
} else {
scrollup(nlines);
}
updateNextscreen(VALID);
}
Cursrow = Curscol = Cursvcol = i = 0;
for (p = Topchar; p->linep != Curschar->linep; p = nextline(p))
Cursrow += LineSizes[i++];
if (P(P_NU))
Curscol = 8;
Cline_row = Cursrow;
if (i >= NumLineSizes) { /* Should only happen with a line that is too
* long to fit on the last screen line. */
Cline_size = 0;
} else {
Cline_size = LineSizes[i];
for (i = 0; i <= Curschar->index; i++) {
c = Curschar->linep->s[i];
/* A tab gets expanded, depending on the current column */
if (c == TAB && !P(P_LS))
incr = P(P_TS) - (Cursvcol % P(P_TS));
else
incr = chars[c].ch_size;
Curscol += incr;
Cursvcol += incr;
if (Curscol >= Columns) {
Curscol -= Columns;
Cursrow++;
didincr = TRUE;
} else
didincr = FALSE;
}
if (didincr)
Cursrow--;
if (c == TAB && State == NORMAL && !P(P_LS)) {
Curscol--;
Cursvcol--;
} else {
Curscol -= incr;
Cursvcol -= incr;
}
if (Curscol < 0)
Curscol += Columns;
}
if (set_want_col) {
Curswant = Cursvcol;
set_want_col = FALSE;
}
}
/*
* The rest of the routines in this file perform screen manipulations. The
* given operation is performed physically on the screen. The corresponding
* change is also made to the internal screen image. In this way, the editor
* anticipates the effect of editing changes on the appearance of the screen.
* That way, when we call screenupdate a complete redraw isn't usually
* necessary. Another advantage is that we can keep adding code to anticipate
* screen changes, and in the meantime, everything still works.
*/
/*
* s_ins(row, nlines, total_rows, columns) - insert 'nlines' lines at 'row'
*/
void
s_ins(row, nlines, total_rows, columns)
int row;
int nlines;
int total_rows;
int columns;
{
register char *s; /* src for block copy */
register char *d; /* dest for block copy */
register char *e; /* end point for copy */
int i;
if (nlines > (total_rows - 1 - row))
nlines = total_rows - 1 - row;
if ((T_IL[0] == NUL) || RedrawingDisabled || nlines <= 0)
return;
/*
* It "looks" better if we do all the inserts at once
*/
outstr(T_SC); /* save position */
if (T_IL_B[0] == NUL) {
for (i = 0; i < nlines; i++) {
windgoto(row, 0);
outstr(T_IL);
}
} else {
windgoto(row, 0);
outstr(T_IL);
if (nlines >= 10)
outchar((char) (nlines / 10 + '0'));
outchar((char) (nlines % 10 + '0'));
outstr(T_IL_B);
}
windgoto(total_rows - 1, 0); /* delete any garbage that may have */
outstr(T_EL); /* been shifted to the bottom line */
outstr(T_RC); /* restore the cursor position */
/*
* Now do a block move to update the internal screen image
*/
d = Realscreen + (columns * (total_rows - 1)) - 1;
s = d - (columns * nlines);
e = Realscreen + (columns * row);
while (s >= e)
*d-- = *s--;
/*
* Clear the inserted lines
*/
s = Realscreen + (row * columns);
e = s + (nlines * columns);
while (s < e)
*s++ = ' ';
}
/*
* s_del(row, nlines, total_rows, columns) - delete 'nlines' lines at 'row'
*/
void
s_del(row, nlines, total_rows, columns)
int row;
int nlines;
int total_rows;
int columns;
{
register char *s;
register char *d;
register char *e;
int i;
if (nlines > (total_rows - 1 - row))
nlines = total_rows - 1 - row;
if ((T_DL[0] == NUL) || RedrawingDisabled || nlines <= 0)
return;
outstr(T_SC); /* save position */
windgoto(total_rows - 1, 0); /* delete any garbage that */
outstr(T_EL); /* was on the status line */
/* delete the lines */
if (T_DL_B[0] == NUL) {
for (i = 0; i < nlines; i++) {
windgoto(row, 0);
outstr(T_DL); /* delete a line */
}
} else {
windgoto(row, 0);
outstr(T_DL);
if (nlines >= 10)
outchar((char) (nlines / 10 + '0'));
outchar((char) (nlines % 10 + '0'));
outstr(T_DL_B);
}
outstr(T_RC); /* restore position */
/*
* do a block move to update the internal image
*/
d = Realscreen + (row * columns);
s = d + (nlines * columns);
e = Realscreen + ((total_rows - 1) * columns);
while (s < e)
*d++ = *s++;
while (d < e) /* clear the lines at the bottom */
*d++ = ' ';
}
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.